package com.jingxuan.interceptor;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.jingxuan.common.annotation.NoAuth;
import com.jingxuan.common.annotation.RequirePermission;
import com.jingxuan.common.annotation.RequireRole;
import com.jingxuan.common.constant.RedisKeyConstants;
import com.jingxuan.common.result.Result;
import com.jingxuan.common.result.ResultCode;
import com.jingxuan.dto.response.UserInfoResponse;
import com.jingxuan.service.UserService;
import com.jingxuan.util.JwtUtil;
import com.jingxuan.util.PermissionCheckUtil;
import com.jingxuan.util.RedisUtil;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

/**
 * 认证拦截器
 */
@Slf4j
@Component
public class AuthInterceptor implements HandlerInterceptor {
    
    @Autowired
    private JwtUtil jwtUtil;
    
    @Autowired
    private RedisUtil redisUtil;
    
    @Autowired
    private UserService userService;
    
    /**
     * 用于存储当前请求的用户信息
     */
    private static final ThreadLocal<Map<String, Object>> USER_CONTEXT = new ThreadLocal<>();
    
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        // 处理OPTIONS请求
        if ("OPTIONS".equals(request.getMethod())) {
            return true;
        }
        
        // 如果不是方法处理器，直接放行
        if (!(handler instanceof HandlerMethod)) {
            return true;
        }
        
        HandlerMethod handlerMethod = (HandlerMethod) handler;
        
        // 检查是否标注了@NoAuth注解
        NoAuth noAuthOnMethod = handlerMethod.getMethodAnnotation(NoAuth.class);
        NoAuth noAuthOnClass = handlerMethod.getBeanType().getAnnotation(NoAuth.class);
        if (noAuthOnMethod != null || noAuthOnClass != null) {
            log.debug("接口标注了@NoAuth，无需认证");
            return true;
        }
        
        // 从Header中获取Token
        String authHeader = request.getHeader("Authorization");
        if (authHeader == null || authHeader.trim().isEmpty()) {
            log.warn("请求未携带Token，URI: {}", request.getRequestURI());
            responseError(response, ResultCode.UNAUTHORIZED, "请先登录");
            return false;
        }
        
        // 支持 "Bearer token" 和直接传 "token" 两种格式
        String token = authHeader.trim();
        if (token.startsWith("Bearer ")) {
            token = token.substring(7).trim();
        }
        
        // 验证Token
        if (!jwtUtil.validateToken(token)) {
            log.warn("Token验证失败，URI: {}", request.getRequestURI());
            responseError(response, ResultCode.UNAUTHORIZED, "登录已过期，请重新登录");
            return false;
        }
        
        // 从Token中获取用户ID
        Long userId = jwtUtil.getUserIdFromToken(token);
        if (userId == null) {
            log.warn("Token中无法获取用户ID");
            responseError(response, ResultCode.UNAUTHORIZED, "无效的登录信息");
            return false;
        }
        
        // 从Redis中验证Token是否存在（是否已登出）
        String redisKey = RedisKeyConstants.getTokenKey(userId);
        Object redisToken = redisUtil.get(redisKey);
        if (redisToken == null || !token.equals(redisToken.toString())) {
            log.warn("Token已失效或已登出，userId: {}", userId);
            responseError(response, ResultCode.UNAUTHORIZED, "登录已失效，请重新登录");
            return false;
        }
        
        // 从Token获取角色信息
        String rolesStr = jwtUtil.getRolesFromToken(token);
        List<String> roles = rolesStr != null ? Arrays.asList(rolesStr.split(",")) : List.of();
        
        // 将用户信息存入ThreadLocal
        Map<String, Object> userInfo = Map.of(
                "userId", userId,
                "userName", jwtUtil.getUserNameFromToken(token),
                "roles", rolesStr != null ? rolesStr : ""
        );
        USER_CONTEXT.set(userInfo);
        
        // 检查角色权限
        if (!checkRolePermission(handlerMethod, userId, roles, response)) {
            return false;
        }
        
        // 检查操作权限
        if (!checkOperationPermission(handlerMethod, userId, response)) {
            return false;
        }
        
        return true;
    }
    
    /**
     * 检查角色权限
     */
    private boolean checkRolePermission(HandlerMethod handlerMethod, Long userId, List<String> userRoles, HttpServletResponse response) throws IOException {
        // 先检查方法上的注解
        RequireRole requireRoleOnMethod = handlerMethod.getMethodAnnotation(RequireRole.class);
        RequireRole requireRoleOnClass = handlerMethod.getBeanType().getAnnotation(RequireRole.class);
        
        RequireRole requireRole = requireRoleOnMethod != null ? requireRoleOnMethod : requireRoleOnClass;
        
        if (requireRole != null) {
            String[] requiredRoles = requireRole.value();
            boolean requireAll = requireRole.requireAll();
            
            boolean hasPermission;
            if (requireAll) {
                // 需要拥有所有角色
                hasPermission = Arrays.stream(requiredRoles)
                        .allMatch(userRoles::contains);
            } else {
                // 只需拥有任意一个角色
                hasPermission = PermissionCheckUtil.hasAnyRole(userRoles, requiredRoles);
            }
            
            if (!hasPermission) {
                log.warn("用户权限不足，userId: {}, 需要角色: {}, 用户角色: {}", 
                        userId, Arrays.toString(requiredRoles), userRoles);
                responseError(response, ResultCode.FORBIDDEN, "您没有权限访问该接口");
                return false;
            }
            
            log.debug("角色权限检查通过，userId: {}, 需要角色: {}", userId, Arrays.toString(requiredRoles));
        }
        
        return true;
    }
    
    /**
     * 检查操作权限
     */
    private boolean checkOperationPermission(HandlerMethod handlerMethod, Long userId, HttpServletResponse response) throws IOException {
        // 先检查方法上的注解
        RequirePermission requirePermissionOnMethod = handlerMethod.getMethodAnnotation(RequirePermission.class);
        RequirePermission requirePermissionOnClass = handlerMethod.getBeanType().getAnnotation(RequirePermission.class);
        
        RequirePermission requirePermission = requirePermissionOnMethod != null ? requirePermissionOnMethod : requirePermissionOnClass;
        
        if (requirePermission != null) {
            // 从数据库查询用户权限
            UserInfoResponse userInfo = userService.getUserById(userId);
            List<String> userPermissions = userInfo.getPermissions();
            
            String[] requiredPermissions = requirePermission.value();
            boolean requireAll = requirePermission.requireAll();
            
            boolean hasPermission;
            if (requireAll) {
                // 需要拥有所有权限
                hasPermission = PermissionCheckUtil.hasAllPermissions(userPermissions, requiredPermissions);
            } else {
                // 只需拥有任意一个权限
                hasPermission = PermissionCheckUtil.hasAnyPermission(userPermissions, requiredPermissions);
            }
            
            if (!hasPermission) {
                log.warn("用户权限不足，userId: {}, 需要权限: {}, 用户权限: {}", 
                        userId, Arrays.toString(requiredPermissions), userPermissions);
                responseError(response, ResultCode.FORBIDDEN, "您没有权限执行该操作");
                return false;
            }
            
            log.debug("操作权限检查通过，userId: {}, 需要权限: {}", userId, Arrays.toString(requiredPermissions));
        }
        
        return true;
    }
    
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
        // 清除ThreadLocal，防止内存泄漏
        USER_CONTEXT.remove();
    }
    
    /**
     * 获取当前登录用户ID
     */
    public static Long getCurrentUserId() {
        Map<String, Object> userInfo = USER_CONTEXT.get();
        return userInfo != null ? (Long) userInfo.get("userId") : null;
    }
    
    /**
     * 获取当前登录用户名
     */
    public static String getCurrentUserName() {
        Map<String, Object> userInfo = USER_CONTEXT.get();
        return userInfo != null ? (String) userInfo.get("userName") : null;
    }
    
    /**
     * 获取当前用户角色
     */
    public static String getCurrentUserRoles() {
        Map<String, Object> userInfo = USER_CONTEXT.get();
        return userInfo != null ? (String) userInfo.get("roles") : null;
    }
    
    /**
     * 返回错误信息（自定义消息）
     */
    private void responseError(HttpServletResponse response, ResultCode resultCode, String message) throws IOException {
        response.setContentType("application/json;charset=UTF-8");
        
        // 根据不同的错误码设置HTTP状态码
        if (resultCode == ResultCode.UNAUTHORIZED) {
            response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); // 401
        } else if (resultCode == ResultCode.FORBIDDEN) {
            response.setStatus(HttpServletResponse.SC_FORBIDDEN); // 403
        } else {
            response.setStatus(HttpServletResponse.SC_BAD_REQUEST); // 400
        }
        
        Result<?> result = Result.error(resultCode.getCode(), message);
        ObjectMapper mapper = new ObjectMapper();
        String jsonResult = mapper.writeValueAsString(result);
        
        PrintWriter writer = response.getWriter();
        writer.write(jsonResult);
        writer.flush();
    }
}

